#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>

#define BUFFER_SIZE 1024
#define PORT 0

// 校验和
unsigned short checksum(unsigned short *buf, int size) {
    unsigned long cksum = 0;
    while (size > 1) {
        cksum += *buf++;
        size -= sizeof(unsigned short);
    }
    if (size) {
        cksum += *(unsigned char *)buf;
    }
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);
    return (unsigned short)(~cksum);
}

int main() {
    int sockfd;
    struct sockaddr_in servaddr;
    char buffer[BUFFER_SIZE];

    if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
        perror("socket creation failed");
        return -1;
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    servaddr.sin_port = htons(PORT);

    struct icmphdr *icmp_hdr = (struct icmphdr *)buffer;
    icmp_hdr->type = ICMP_ECHO;
    icmp_hdr->code = 0;
    icmp_hdr->checksum = 0;
    icmp_hdr->un.echo.id = getpid();
    icmp_hdr->un.echo.sequence = 1;
    icmp_hdr->checksum = checksum((unsigned short *)icmp_hdr, sizeof(struct icmphdr));

    if (sendto(sockfd, buffer, sizeof(struct icmphdr), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
        perror("sendto");
        close(sockfd);
        return -1;
    }

    socklen_t len = sizeof(servaddr);
    int n = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&servaddr, &len);
    if (n < 0) {
        perror("recvfrom");
    } else {
        struct icmphdr *icmp_hdr = (struct icmphdr *)(buffer + sizeof(struct iphdr));
        if (icmp_hdr->type == ICMP_ECHOREPLY) {
            std::cout << "Received time: " << buffer + sizeof(struct iphdr) + sizeof(struct icmphdr) << std::endl;
        }
    }

    close(sockfd);
    return 0;
}
    